package itsm.isperp.module.service.configuration;

import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.DataResponse;
import itsm.isperp.framework.domain.IUser;
import itsm.isperp.framework.service.BaseService;
import itsm.isperp.framework.utils.BeanUtils;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.utils.JsonBuilder;
import itsm.isperp.framework.web.request.JqGridFilterRuleOp;
import itsm.isperp.framework.web.request.JqGridRequest;
import itsm.isperp.module.dto.configuration.ConfCiPropertyDTO;
import itsm.isperp.module.dto.configuration.ConfCiRelationDTO;
import itsm.isperp.module.dto.configuration.ConfCiRelationTypeDTO;
import itsm.isperp.module.entity.configuration.ConfCi;
import itsm.isperp.module.entity.configuration.ConfCiProperty;
import itsm.isperp.module.entity.configuration.ConfCiRelationHistory;
import itsm.isperp.module.entity.configuration.ConfCiRelationPlan;
import itsm.isperp.module.entity.configuration.ConfCiRelationUsePropety;
import itsm.isperp.module.repository.configuration.ConfCiRelationPlanMapper;
import itsm.isperp.module.utils.CiProprtyUtils;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

/**
 * 配置关系服务
 * 
 * @author lizx
 * @date 2014-09-22 09:52
 */
@Service
public class ConfCiRelationPlanService extends BaseService<ConfCiRelationPlan> {

	@Autowired
	protected ConfCiRelationPlanMapper confCiRelationPlanMapper;

	@Autowired
	protected ConfCiPropertyService confCiPropertyService;

	@Autowired
	protected ConfCiRelationTypeService confCiRelationTypeService;

	@Autowired
	protected ConfCiRelationUsePropetyService confCiRelationUsePropetyService;

	@Autowired
	protected ConfCiRelationHistoryService confCiRelationHistoryService;

	@Autowired
	protected ConfCiService confCiService;

	@Autowired
	protected JdbcTemplate jdbcTemplate;

	@Override
	public ConfCiRelationPlanMapper getRepository() {
		return this.confCiRelationPlanMapper;
	}

	/**
	 * ci关系删除,日志记录
	 */
	public void delete(String changeId, String id) {

		ConfCiRelationHistory he = new ConfCiRelationHistory();
		ConfCiRelationPlan entity = this.findOne(id);

		he.setFromId(entity.getFromId());
		he.setToId(entity.getToId());
		he.setRelationTypeId(entity.getRelationTypeId());
		he.setrCreateDate(entity.getCreateDate());
		he.setrCreator(entity.getCreator());
		he.setCreatorName(entity.getCreatorName());
		try {
			ConfCi fromCi = this.confCiService.findOne(entity.getFromId());
			ConfCi toCi = this.confCiService.findOne(entity.getToId());

			String fromDesc = BeanUtils.getDatalogDescription(fromCi,
					ConfCi.class);
			String toDesc = BeanUtils.getDatalogDescription(toCi, ConfCi.class);

			he.setDescriptionFrom(fromDesc);
			he.setDescriptionTo(toDesc);

			List<ConfCiPropertyDTO> fromCIProperties = this.confCiPropertyService
					.findDatailByCiId(fromCi.getId());
			List<ConfCiPropertyDTO> toCIProperties = this.confCiPropertyService
					.findDatailByCiId(toCi.getId());

			he.setDataJsonFrom(JsonBuilder.buildNormalBinder().toJson(fromCi));
			he.setDataJsonTo(JsonBuilder.buildNormalBinder().toJson(toCi));

			he.setDescriptionFromProp(CiProprtyUtils
					.getPropertyDescription(fromCIProperties));
			he.setDescriptionFromProp(CiProprtyUtils
					.getPropertyDescription(toCIProperties));

			this.confCiRelationHistoryService.saveOrUpdate(he);
		} catch (Exception e) {
			he.setModifier(e.toString());
			this.confCiRelationHistoryService.saveOrUpdate(he);
		}

		this.getRepository().deleteByClass(id, ConfCiRelationPlan.class);

		autoUpdateCiProperty(changeId, entity.getFromId(), entity);

	}

	public List<ConfCiRelationPlan> findByFromId(String fromId) {
		return this.confCiRelationPlanMapper.findByFromId(fromId);
	}

	public List<ConfCiRelationPlan> findByToId(String toId) {
		return this.confCiRelationPlanMapper.findByToId(toId);
	}

	public List<ConfCiRelationPlan> findByFromIdWithSource(String fromId) {
		return this.confCiRelationPlanMapper.findByFromIdAndUsePropertyType(
				fromId, "0");
	}

	public List<ConfCiRelationPlan> findByToIdWithSource(String toId) {
		return this.confCiRelationPlanMapper.findByToIdAndUsePropertyType(toId,
				"1");
	}

	public List<ConfCiRelationPlan> findByFromIdAndUsePropertyType(
			String fromId, String usePropertyType) {
		return this.confCiRelationPlanMapper.findByFromIdAndUsePropertyType(
				fromId, usePropertyType);
	}

	public List<ConfCiRelationPlan> findByToIdAndUsePropertyType(String toId,
			String usePropertyType) {
		return this.confCiRelationPlanMapper.findByToIdAndUsePropertyType(toId,
				usePropertyType);
	}

	public ConfCiRelationPlan findRelation(String fromId,
			String fromCategoryId, String toCategoryId) {
		return this.confCiRelationPlanMapper.findRelation(fromId,
				fromCategoryId, toCategoryId);
	}

	public List<ConfCiRelationDTO> findDtoByFromIdWidthSource(String fromId) {

		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);

		req.addFilterRule("from_id", JqGridFilterRuleOp.eq, fromId);

		return this.confCiRelationPlanMapper.findDtoByRequest(req);
	}

	public List<ConfCiRelationDTO> findDtoByToIdWidthSource(String fromId) {

		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);

		req.addFilterRule("to_id", JqGridFilterRuleOp.eq, fromId);
		req.addFilterRule("use_property_type", JqGridFilterRuleOp.eq, "1");

		return this.confCiRelationPlanMapper.findDtoByRequest(req);
	}

	public DataResponse<ConfCiRelationDTO> findDtoByRequest(DataRequest request) {
		return this.confCiRelationPlanMapper.findDtoByRequest(request);
	}

	// a变化，b关联的属性也要变化
	// 对于包含关系和关联关系是不一样的处理方式
	// 包含方式a->写入b
	// 关联方式b->写入a
	public void batchSave(String changeId, String relationTypeId,
			String fromId, String[] toIdArr) {
		// 获取所有映射关系
		// 有to_id中的值重写from_id的值

		// 获取下级所有（1、关联；2、类型、3属性）
		// eg.交换机->交换机端口
		// 1、交换机关联到多个交换机端口
		// 2、选择每个端口的值
		if (toIdArr != null) {
			for (String s : toIdArr) {
				ConfCiRelationPlan r = new ConfCiRelationPlan();
				r.setRelationTypeId(relationTypeId);
				r.setFromId(fromId);
				r.setToId(s);
				this.saveOrUpdate(r);

				this.autoUpdateCiProperty(changeId, fromId, r);
			}

		}

	}

	/**
	 * 
	 * @param relation
	 * @param up
	 * @return
	 */
	public List<ConfCiProperty> getCiRelationAndProperty(
			ConfCiRelationPlan relation, ConfCiRelationUsePropety up) {
		List<ConfCiRelationPlan> rs = null;

		String relationTypeId = up.getRelationTypeId();

		// a->b
		if (up.getUsePropertyType() == 1) {
			rs = this.confCiRelationPlanMapper.findByFromIdAndRelationTypeId(
					relation.getFromId(), relationTypeId);

			// 找到b的属性及属性值
			for (ConfCiRelationPlan r : rs) {
				ConfCiProperty toP = this.confCiPropertyService
						.findByCiIdAndPropertyId(r.getToId(),
								up.getToPropertyId());
				if (toP == null) {
					if (toP == null) {
						toP = new ConfCiProperty();
						toP.setConfCategoryPropertyId(up.getToPropertyId());
						toP.setConfCiId(r.getToId());
					}

					this.confCiPropertyService.saveOrUpdate(toP);
				}
			}

			if (rs.size() == 0) {
				return null;
			}
			String[] arr = new String[rs.size()];

			for (int i = 0; i < arr.length; i++) {
				arr[i] = rs.get(i).getToId();
			}
			return this.confCiPropertyService.findByCiIdsAndPropetyId(arr,
					up.getToPropertyId());

		} else {
			rs = this.confCiRelationPlanMapper
					.findByRelationTypeId(relationTypeId);

			if (rs.size() == 0) {
				return null;
			}
			String[] arr = new String[rs.size()];

			for (int i = 0; i < arr.length; i++) {
				arr[i] = rs.get(i).getToId();
			}
			return this.confCiPropertyService.findByCiIdsAndPropetyId(arr,
					up.getToPropertyId());

		}

	}

	public void autoUpdateCiProperty(String changeId, ConfCiRelationPlan r,
			List<ConfCiRelationUsePropety> ups) {
		for (ConfCiRelationUsePropety up : ups) {

			// 从from中写入到to中
			List<ConfCiProperty> lp = this.getCiRelationAndProperty(r, up);

			// 针对字段(只能支持a写入b)
			if (up.getFromPropertyId().contains("field-")) {

				String column = up.getFromPropertyId().substring(6);

				Map<String, Object> map = this.confCiService.findOneToMap(
						r.getFromId(), column);
				if (map == null) {
					continue;
				}
				Object v = map.get(column);

				if (lp != null && lp.size() > 0) {
					for (ConfCiProperty p : lp) {
						p.setValue(v == null ? "" : v.toString());
						// this.confCiService.savePropertyChageLog(null,null,fromP)
						this.confCiPropertyService.saveOrUpdate(p);
					}
				}

			} else if (up.getUsePropertyType() == 1) {
				// 有a->b

				ConfCiProperty fromP = this.confCiPropertyService
						.findByCiIdAndPropertyId(r.getFromId(),
								up.getFromPropertyId());

				if (fromP == null) {
					fromP = new ConfCiProperty();
					fromP.setConfCategoryPropertyId(up.getFromPropertyId());
					fromP.setConfCiId(r.getFromId());
				}

				// 1、找到到关联到a的下的某一类关联属性的设备；
				// 2、为各个ci重新写入属性数据；
				// 2.1、先删除这一属性，然后再重写
				if (lp != null && lp.size() > 0) {
					for (ConfCiProperty p : lp) {
						p.setValue(fromP == null ? "" : fromP.getValue());
						// this.confCiService.savePropertyChageLog(null,null,fromP)
						this.confCiPropertyService.saveOrUpdate(p);
					}
				}

			} else if (up.getUsePropertyType() == 0) {
				// 由b->a
				// 1、获取到关联到a的某一类关联属性的设备；
				// 2、组合其数据，然后修改属性
				ConfCiProperty fromP = this.confCiPropertyService
						.findByCiIdAndPropertyId(r.getFromId(),
								up.getFromPropertyId());
				String val = "";
				if (lp != null && lp.size() > 0) {

					for (int i = 0; i < lp.size(); i++) {
						String vv = lp.get(i).getValue();
						if (StringUtils.isNotEmpty(vv)) {
							val += "," + lp.get(i).getValue();
						}
					}
					if (val.length() > 0)
						val = val.substring(1);

				}

				if (fromP == null) {
					fromP = new ConfCiProperty();
					fromP.setConfCiId(r.getFromId());
					fromP.setConfCategoryPropertyId(up.getFromPropertyId());
				}
				fromP.setValue(val);
				this.confCiPropertyService.saveOrUpdate(fromP);
			}

		}
	}

	/**
	 * 当某个ci数据变化后
	 * 
	 * @param ciId
	 */
	public void autoUpdateCiProperty(String changeId, String ciId) {
		// 有ci找到两种情况的数据
		List<ConfCiRelationUsePropety> cps = this.confCiRelationUsePropetyService
				.findByFromIdOrToId(ciId);

		this.autoUpdateCiProperty(changeId, ciId, cps);

	}

	public void autoUpdateCiProperty(String changeId, String ciId,
			List<ConfCiRelationUsePropety> ups) {
		List<ConfCiRelationPlan> rs = this.confCiRelationPlanMapper
				.findByFromIdOrToId(ciId);

		for (ConfCiRelationPlan r : rs) {
			autoUpdateCiProperty(changeId, r, ups);
		}

	}

	public void autoUpdateCiProperty(String changeId, String ciId,
			ConfCiRelationPlan r) {
		//
		// ConfCiRelationType rt = this.confCiRelationTypeService
		// .findOne(relationTypeId);

		// 如果pt为0则表示有from的值写入到to中
		// 如果pt的值为1表示to的值写入到from中
		// String pt = rt.getUsePropertyType();
		// List<ConfCiProperty> lp = this.confCiRelationPlanMapper
		// .findByFromIdAndRelationTypeId(fromId, relationTypeId);
		List<ConfCiRelationUsePropety> ups = this.confCiRelationUsePropetyService
				.findByFromIdAndRelationTypeId(ciId, r.getRelationTypeId());
		autoUpdateCiProperty(changeId, r, ups);

	}

	public void deleteByRelationTypeId(String relationTypeId) {
		this.confCiRelationPlanMapper.deleteByRelationTypeId(relationTypeId);
	}

	public void deleteByFromId(String fromId) {
		this.confCiRelationPlanMapper.deleteByFromId(fromId);

	}

	/**
	 * 重新构建指定ci的关联关系
	 * 
	 * @param fromId
	 * @throws Exception
	 */
	public void rebuildCiRelationByCi(String fromId, String changeId)
			throws Exception {

		this.deleteByFromId(fromId);
		ConfCi ci = this.confCiService.findOne(fromId);

		List<ConfCiRelationTypeDTO> list = this.confCiRelationTypeService
				.findAllDTOByFromCategoyId(ci.getConfCategoryId());
		this.rebuildCiRelation(list, fromId, changeId);
	}

	/**
	 * 重新构建指定分类的关联关系
	 * 
	 * @param relationTypeId
	 * @throws Exception
	 */
	public void rebuildCiRelationByRelationType(String relationTypeId)
			throws Exception {

		this.deleteByRelationTypeId(relationTypeId);

		List<ConfCiRelationTypeDTO> list = this.confCiRelationTypeService
				.findOneDTO(relationTypeId);
		this.rebuildCiRelation(list, null, null);
	}

	/**
	 * 重新构建ci关联关系
	 * 
	 * @throws Exception
	 */
	public void rebuildCiRelation() throws Exception {

		// 先删除原有的
		this.deleteAll();
		// 1、获取所有关联及其关联的映射字段
		// 2、根据映射，获取所有ci及属性（根据映射的类别及属性的值判断）
		// 2.1、如服务器->硬盘，首先获取所有的服务器及其映射属性；
		// 2.2、对于每一个服务器，根据映射关系及其属性值获取映射的硬盘；
		// 2.3、对于每一个符合条件的服务器和硬盘建立关联关系

		List<ConfCiRelationTypeDTO> list = this.confCiRelationTypeService
				.findAllDTO();
		this.rebuildCiRelation(list, null, null);
	}

	/**
	 * 重新构建ci关联关系
	 * 
	 * @throws Exception
	 */
	public void rebuildCiRelation(List<ConfCiRelationTypeDTO> list,
			String fromId, String changeId) throws Exception {

		List<Object[]> args = new ArrayList<>();
		Timestamp now = new Timestamp(new Date().getTime());

		IUser user = ContextHolder.getLoginUser();
		for (ConfCiRelationTypeDTO dto : list) {
			List<ConfCiRelationUsePropety> ps = dto.getProperties();

			// 根据分类获取
			List<ConfCi> fromCis = null;
			if (fromId == null) {
				fromCis = this.confCiService.findByCategory(dto
						.getFromCategoryId());
			} else {
				fromCis = new ArrayList<>();
				fromCis.add(this.confCiService.findOne(fromId));
			}

			// 对于每一个ci，先获取所有from属性的值
			for (ConfCi ci : fromCis) {
				Map<String, String> map = new HashMap<>();

				Map<String, String> toProperties = new HashMap<>();

				for (int i = 0; i < ps.size(); i++) {
					ConfCiRelationUsePropety p = ps.get(i);
					if (p.getUseForRelation()) {
						// 如果不是b写入a
						if (p.getUsePropertyType() != 0) {
							if (p.getFromPropertyId().contains("field-")) {

								String value = org.apache.commons.beanutils.BeanUtils
										.getProperty(
												ci,
												itsm.isperp.framework.utils.StringUtils
														.camelCaseWord(p
																.getFromPropertyId()
																.substring(6)));
								toProperties.put(p.getToPropertyId(), value);
							} else {
								map.put(p.getFromPropertyId(),
										p.getToPropertyId());
							}
						} else if (p.getUsePropertyType() == 0) {
							// b->a
							// 此类型不做处理
						}
					}
				}

				if (map.size() > 0) {

					String[] fromPIds = new String[map.size()];
					List<ConfCiProperty> fromPs = this.confCiPropertyService
							.findByCiIdAndPropertyIds(ci.getId(), map.keySet()
									.toArray(fromPIds));

					for (ConfCiProperty p : fromPs) {
						toProperties.put(
								map.get(p.getConfCategoryPropertyId()),
								p.getValue());
					}
				}

				if (toProperties.size() == 0) {
					continue;
				}

				// 被关联的项目
				List<String> toCis = this.confCiService
						.findCiIdsByProperties(toProperties);

				this.autoUpdateCiProperty(null, fromId);

				if (toCis.size() == 0) {
					continue;
				}

				for (String toCiId : toCis) {

					// ConfCiRelationPlan entity = new ConfCiRelationPlan();
					// entity.setFromId(ci.getId());
					// entity.setRelationTypeId(dto.getId());
					// entity.setToId(toCi.getId());
					// // 创建一条新的关联关系
					// this.confCiRelationService.saveOrUpdate(entity);
					Object[] arg = new Object[10];
					arg[0] = HibernateUUIDGenerator.generate();
					arg[1] = ci.getId();
					arg[2] = toCiId;
					arg[3] = dto.getId();
					arg[4] = user.getUsername();
					arg[5] = user.getFullname();
					arg[6] = now;
					arg[7] = user.getUsername();
					arg[8] = user.getFullname();
					arg[9] = now;
					args.add(arg);
				}
			}
		}
		String sql = "INSERT INTO conf_ci_relation_plan(id,from_id,to_id,relation_type_id,creator,creator_name,create_date,modifier,modifier_name,modify_date) VALUES(?,?,?,?,?,?,?,?,?,?)";
		if (args.size() > 0) {

			this.jdbcTemplate.batchUpdate(sql, args);
		}
	}

	public List<Map<String, Object>> listCiRelation(String ciId, String changeId) {
		String sql = "select distinct b.id AS relation_type_id,b.from_category_id,b.to_category_id,b.from_category_alias_name,b.to_category_alias_name,case when '"
				+ ciId
				+ "'=a.to_id then 'to_ci' else 'from_ci' end AS ci_relation_type  from conf_ci_relation_plan a"
				+ " left join conf_ci_relation_type b on a.RELATION_TYPE_ID=b.id"
				+ " where (a.from_id='"
				+ ciId
				+ "' or a.to_id='"
				+ ciId
				+ "') and change_id='" + changeId + "'";
		return jdbcTemplate.queryForList(sql);
	}

	public List<Map<String, Object>> listCiRelationType(String categoryId) {
		ConfCategoryService confCategoryService = ContextHolder
				.getSpringBean("confCategoryService");

		String treePath = confCategoryService.findOne(categoryId)
				.getTreenodePath();

		String[] pathArr = treePath.split("/");
		String str = "'" + pathArr[0] + "'";
		for (int i = 1; i < pathArr.length - 1; i++) {
			str += "'" + pathArr[i] + "',";
		}
		str = str.substring(0, str.length() - 1);

		String sql = "SELECT * FROM (SELECT a.*, 1 as relation_way FROM conf_ci_relation_type a  WHERE from_category_id IN ("
				+ str
				+ ")"
				+ "union all "
				+ "SELECT  a.*, 0 as relation_way "
				+ "FROM conf_ci_relation_type a "
				+ " where to_category_id IN "
				+ " (" + str + ")" + ")a  ORDER BY a.name";

		return jdbcTemplate.queryForList(sql); 
	}

	public List<Map<String, Object>> listCiRelationTypeByCiId(String ciId) {
		String categoryId = this.confCiService.findOne(ciId)
				.getConfCategoryId();
		String sql = "select '"
				+ categoryId
				+ "' as conf_category_id,a.*,b.treenode_path as from_treenode_path,c.treenode_path as to_treenode_path from  conf_ci_relation_type a left join conf_category b on a.from_category_id=b.id left join conf_category c on a.to_category_id=c.id where b.treenode_path like '%"
				+ categoryId + "%' or c.treenode_path like '%" + categoryId
				+ "%'";
		return jdbcTemplate.queryForList(sql);
	}

	public void copyRelationByCiId(String ciId, String changeId) {
		String sql = "insert into conf_ci_relation_plan(ID,FROM_ID,TO_ID,RELATION_TYPE_ID,CREATOR,CREATOR_NAME,CREATE_DATE,MODIFIER,MODIFIER_NAME,MODIFY_DATE,CHANGE_ID,ARE_NEW,CI_ID)"
				+ " SELECT ID,FROM_ID,TO_ID,RELATION_TYPE_ID,CREATOR,CREATOR_NAME,CREATE_DATE,MODIFIER,MODIFIER_NAME,MODIFY_DATE,'"
				+ changeId
				+ "',0,'"
				+ ciId
				+ "'"
				+ " FROM conf_ci_relation WHERE (FROM_ID='"
				+ ciId
				+ "' OR TO_ID='"
				+ ciId
				+ "') and (not exists(select 1 from conf_ci_relation_plan where change_id='"
				+ changeId + "' and ci_id='" + ciId + "'))";
		jdbcTemplate.execute(sql);
	}

	public void updateRelateStatus(String id, String opType) {
		String sql = "";
		if (opType.equals("ciDelete")) {
			sql = "update conf_ci_relation_plan set op_type=null where id='"
					+ id + "'";
		} else if (opType.equals("ciAdd")) {
			sql = "delete conf_ci_relation_plan where id='" + id + "'";
		} else {
			sql = "update conf_ci_relation_plan set op_type='ciDelete' where id='"
					+ id + "'";
		}
		jdbcTemplate.execute(sql);
	}

	public Integer getPlanChgCiRelateCount(String ciId, String changeId) {
		String sql = "select count(1) countnum from conf_ci_relation_plan where ci_id='"
				+ ciId
				+ "' and (op_type='ciAdd' or op_type='ciDelete') and change_id='"
				+ changeId + "'";
		return jdbcTemplate.queryForObject(sql, Integer.class);
	}

	// 获取根据
	public DataResponse<Map<String, Object>> findRelateToCiByRequest(
			JqGridRequest request) {
		return this.getRepository().findRelateToCiByRequest(request);
	}

	public DataResponse<Map<String, Object>> findRelateFromCiByRequest(
			JqGridRequest request) {
		return this.getRepository().findRelateFromCiByRequest(request);
	}
}
